using System;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace Hanoi.Ui
{
    /// <summary>
    /// UI Helpers for the game.
    /// </summary>
    public class GameUI
    {
        private Graphics g;
        private HanoiGame _game;
        private int _width;
        private int _height;
        private Bitmap _bitmap;

        private Pen p = new Pen(Color.Black);

        private int margin = 1;
        private int paddingHorizontal = 1;
        private int towerWidth;

        public const int BLOCK_HEIGHT = 14;
        public const int MAX_BLOCKS = 8;

        public GameUI(HanoiGame game, int width, int height)
        {
            _game = game;
            _width = width;
            _height = height;
            towerWidth = _width / 3;

            _bitmap = new Bitmap(width, height);
            g = Graphics.FromImage(_bitmap);
        }

        public Image GetImage()
        {
            return _bitmap;
        }

        public void Refresh()
        {
            g.Clear(SystemColors.Window);

            /// Line.       _____
            PaintBottomLine();
            /// Lines.      | | |
            for (int i = 0; i < 3; i++)
                PaintStackLine(towerWidth * (2 * i + 1) / 2, i);

            /// Paint Blocks =
            PaintBlocks();
        }

        public void SelectFrom(int columnIndex)
        {
            object o = _game.Towers[columnIndex].Peek();
            if (o != null)
            {
                Hanoi.Components.Disk disk = (Hanoi.Components.Disk)o;
                int tower = columnIndex;
                int position = disk.Position.Y;
                int level = disk.Value;

                PaintSingleBlock(tower, position, level, true);
            }
        }


        private void PaintBlocks()
        {
            for (int x = 0; x < 3; x++)
                for (int y = (_game.Towers[x].Count - 1); y >= 0; y--)
                {
                    object o = _game.Towers[x].ToArray()[y];
                    if (o != null)
                    {
                        Hanoi.Components.Disk d = (Hanoi.Components.Disk)o;
                        PaintSingleBlock(x, y, d.Value);
                    }
                }

        }

        private void PaintSingleBlock(int tower, int position, int level)
        {
            PaintSingleBlock(tower, position, level, false);
        }

        private void PaintSingleBlock(int tower, int position, int level, bool inversedColors)
        {
            int textPadding = 3;
            int extra = (_game.Size - level) * 3;
            int left = towerWidth * tower + paddingHorizontal + extra;
            int width = towerWidth - paddingHorizontal * 2 - extra * 2;
            int top = _height - BLOCK_HEIGHT * (position + 1) - 2 * margin * (position + 1);

            Color ForeColor = Color.Black;
            Color BackColor = Color.Gold;
            if (inversedColors)
            {
                ForeColor = Color.Gold;
                BackColor = Color.Black;
            }

            Brush ForeBrush = new SolidBrush(ForeColor);
            Pen ForePen = new Pen(ForeColor);
            Brush BackBrush = new SolidBrush(BackColor);

            Rectangle rect = new Rectangle(left, top, width, BLOCK_HEIGHT);
            Font font = new Font("Nina", 8f, FontStyle.Bold);

            g.FillRectangle(BackBrush, rect);
            rect.Height -= 1;
            g.DrawRectangle(ForePen, rect);
            g.DrawString(level.ToString(), font, ForeBrush, towerWidth * (2*tower+1)/2 - 2, top - 1);
        }


        private void PaintStackLine(int left, int columnIndex)
        {
            g.FillPolygon(new SolidBrush(GetColor(columnIndex)),
                new Point[] {
                    new Point(left, margin),
                    new Point(left - 10, _height - margin * 2),
                    new Point(left + 10, _height - margin * 2)
                });
            g.FillRectangle(new SolidBrush(GetColor(columnIndex)),
                new Rectangle(left - 4, _height - margin * 2, 8, 8));
        }

        private void PaintBottomLine()
        {
            g.DrawLine(p, paddingHorizontal, _height - margin * 2,
                _width - paddingHorizontal * 2, _height - margin * 2);
        }

        private Color GetColor(int columnIndex)
        {
            if (_game.Start == columnIndex)
                return Color.FromArgb(255, 127, 127);
            else if (_game.End == columnIndex)
                return Color.FromArgb(127, 127, 255);
            else
                return Color.FromArgb(127, 255, 127);
        }
    }
}
